/***
 * @Author: 玄绮 shijiahansi@qq.com
 * @Date: 2024-05-17 16:52:40
 * @LastEditors: 玄绮 shijiahansi@qq.com
 * @LastEditTime: 2024-05-17 16:55:09
 * @FilePath: \server\src\tools\signal.hpp
 * @Description:
 * @
 * @Copyright (c) 2024 by 玄绮, All Rights Reserved.
 */

#if !defined(__SIGNAL_HPP__)
#    define __SIGNAL_HPP__

#    include <boost/bind/bind.hpp>
#    include <boost/bind/placeholders.hpp>
#    include <boost/signals2.hpp>
#    include <boost/type_traits.hpp>
#    include <boost/utility/enable_if.hpp>

// Placeholder namespace
using namespace boost::placeholders;
namespace signald {

    // Helper trait to count function parameters
    template <typename T>
    struct function_traits;

    // Partial specialization for function types
    template <typename R, typename... Args>
    struct function_traits<R(Args...)>
    {
        static const size_t arity = sizeof...(Args);
    };

    // Partial specialization for member function pointers
    template <typename R, typename C, typename... Args>
    struct function_traits<R (C::*)(Args...)>
    {
        static const size_t arity = sizeof...(Args);
    };

#    if 1
    // Overload for functions with no arguments
    template <typename Signal, typename Slot, typename SourceSharedPtr>
    typename boost::enable_if_c<
        function_traits<Slot>::arity == 0>::type
    connect(Signal& signal, Slot slot, SourceSharedPtr source) {
        signal.connect(typename Signal::slot_type(slot, source.get()).track(source));
    }

    // Overload for functions with one argument
    template <typename Signal, typename Slot, typename SourceSharedPtr>
    typename boost::enable_if_c<
        function_traits<Slot>::arity == 1>::type
    connect(Signal& signal, Slot slot, SourceSharedPtr source) {
        signal.connect(typename Signal::slot_type(slot, source.get(), _1).track(source));
    }

    // Overload for functions with two arguments
    template <typename Signal, typename Slot, typename SourceSharedPtr>
    typename boost::enable_if_c<
        function_traits<Slot>::arity == 2>::type
    connect(Signal& signal, Slot slot, SourceSharedPtr source) {
        signal.connect(typename Signal::slot_type(slot, source.get(), _1, _2).track(source));
    }

#    endif

#    if 0
template <typename Signal, typename Slot, typename SourceSharedPtr>
void connect(Signal& signal, Slot slot, SourceSharedPtr source) {
    connect_impl(signal, slot, source, typename function_traits<Slot>::SlotArity());
}

template <typename Signal, typename Slot, typename SourceSharedPtr>
void connect_impl(Signal& signal, Slot slot, SourceSharedPtr source, std::integral_constant<std::size_t, 1>) {
    signal.connect(typename Signal::slot_type(slot, source.get(), _1).track(source));
}

template <typename Signal, typename Slot, typename SourceSharedPtr>
void connect_impl(Signal& signal, Slot slot, SourceSharedPtr source, std::integral_constant<std::size_t, 2>) {
    signal.connect(typename Signal::slot_type(slot, source.get(), _1, _2).track(source));
}

#    endif
}  // namespace signal

#endif  // __SIGNAL_HPP__
